});
},
- _onTrayIconAdded: function(o, icon, wmClass) {
+ _onTrayIconAdded: function(o, icon) {
+ let wmClass = icon.wm_class.toLowerCase();
+
icon.height = PANEL_ICON_SIZE;
let role = STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass];
shell-perf-log.h \
shell-slicer.h \
shell-stack.h \
+ shell-tray-icon.h \
shell-tray-manager.h \
shell-uri-util.h \
shell-window-tracker.h \
shell-perf-log.c \
shell-slicer.c \
shell-stack.c \
+ shell-tray-icon.c \
shell-tray-manager.c \
shell-uri-util.c \
shell-window-tracker.c \
G_DEFINE_TYPE (ShellEmbeddedWindow, shell_embedded_window, GTK_TYPE_WINDOW);
+enum {
+ PROP_0,
+
+ PROP_STAGE
+};
+
struct _ShellEmbeddedWindowPrivate {
ShellGtkEmbed *actor;
GdkRectangle position;
+ Window stage_xwindow;
};
/*
shell_embedded_window_realize (GtkWidget *widget)
{
ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget);
- ClutterActor *stage;
- Window stage_xwindow;
GTK_WIDGET_CLASS (shell_embedded_window_parent_class)->realize (widget);
- stage = clutter_actor_get_stage (CLUTTER_ACTOR (window->priv->actor));
-
- /* Clutter is buggy and will realize an actor when it has a parent
- * but no grandparent; this is a workaround until
- * http://bugzilla.openedhand.com/show_bug.cgi?id=1138 is fixed - we
- * only have one stage in the shell in any case.
- */
- if (!stage)
- stage = clutter_stage_get_default ();
-
- stage_xwindow = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
/* Using XReparentWindow() is simpler than using gdk_window_reparent(),
* since it avoids maybe having to create a new foreign GDK window for
*/
XReparentWindow (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)),
GDK_WINDOW_XWINDOW (gtk_widget_get_window (widget)),
- stage_xwindow,
+ window->priv->stage_xwindow,
window->priv->position.x, window->priv->position.y);
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (window->priv->actor));
}
+static void
+shell_embedded_window_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (object);
+
+ switch (prop_id)
+ {
+ case PROP_STAGE:
+ window->priv->stage_xwindow =
+ clutter_x11_get_stage_window (g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
static GObject *
shell_embedded_window_constructor (GType gtype,
guint n_properties,
g_type_class_add_private (klass, sizeof (ShellEmbeddedWindowPrivate));
+ object_class->set_property = shell_embedded_window_set_property;
object_class->constructor = shell_embedded_window_constructor;
widget_class->show = shell_embedded_window_show;
widget_class->configure_event = shell_embedded_window_configure_event;
container_class->check_resize = shell_embedded_window_check_resize;
+
+ g_object_class_install_property (object_class,
+ PROP_STAGE,
+ g_param_spec_object ("stage",
+ "Stage",
+ "ClutterStage to embed on",
+ CLUTTER_TYPE_STAGE,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
}
static void
window->priv->actor = actor;
- if (gtk_widget_get_visible (GTK_WIDGET (window))
- && CLUTTER_ACTOR_IS_REALIZED (actor))
+ if (actor &&
+ CLUTTER_ACTOR_IS_REALIZED (actor) &&
+ gtk_widget_get_visible (GTK_WIDGET (window)))
gtk_widget_map (GTK_WIDGET (window));
}
* Public API
*/
GtkWidget *
-shell_embedded_window_new (void)
+shell_embedded_window_new (ClutterStage *stage)
{
return g_object_new (SHELL_TYPE_EMBEDDED_WINDOW,
+ "stage", stage,
NULL);
}
#define __SHELL_EMBEDDED_WINDOW_H__
#include <gtk/gtk.h>
+#include <clutter/clutter.h>
#define SHELL_TYPE_EMBEDDED_WINDOW (shell_embedded_window_get_type ())
#define SHELL_EMBEDDED_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_EMBEDDED_WINDOW, ShellEmbeddedWindow))
};
GType shell_embedded_window_get_type (void) G_GNUC_CONST;
-GtkWidget *shell_embedded_window_new (void);
+GtkWidget *shell_embedded_window_new (ClutterStage *stage);
#endif /* __SHELL_EMBEDDED_WINDOW_H__ */
--- /dev/null
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+#include "config.h"
+
+#include "shell-tray-icon.h"
+#include "shell-gtk-embed.h"
+#include "shell-window-tracker.h"
+#include "gtk-compat.h"
+#include "tray/na-tray-child.h"
+#include <gdk/gdkx.h>
+#include "st.h"
+
+enum {
+ PROP_0,
+
+ PROP_PID,
+ PROP_TITLE,
+ PROP_WM_CLASS
+};
+
+struct _ShellTrayIconPrivate
+{
+ NaTrayChild *socket;
+
+ pid_t pid;
+ char *title, *wm_class;
+};
+
+G_DEFINE_TYPE (ShellTrayIcon, shell_tray_icon, SHELL_TYPE_GTK_EMBED);
+
+static void
+shell_tray_icon_finalize (GObject *object)
+{
+ ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
+
+ g_free (icon->priv->title);
+ g_free (icon->priv->wm_class);
+
+ G_OBJECT_CLASS (shell_tray_icon_parent_class)->finalize (object);
+}
+
+static void
+shell_tray_icon_constructed (GObject *object)
+{
+ GdkWindow *icon_app_window;
+ ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
+ ShellEmbeddedWindow *window;
+ GdkDisplay *display;
+ Window plug_xid;
+ Atom _NET_WM_PID, type;
+ int result, format;
+ gulong nitems, bytes_after, *val = NULL;
+
+ /* We do all this now rather than computing it on the fly later,
+ * because the shell may want to see their values from a
+ * tray-icon-removed signal handler, at which point the plug has
+ * already been removed from the socket.
+ */
+
+ g_object_get (object, "window", &window, NULL);
+ g_return_if_fail (window != NULL);
+ icon->priv->socket = NA_TRAY_CHILD (gtk_bin_get_child (GTK_BIN (window)));
+ g_object_unref (window);
+
+ icon->priv->title = na_tray_child_get_title (icon->priv->socket);
+ na_tray_child_get_wm_class (icon->priv->socket, NULL, &icon->priv->wm_class);
+
+ icon_app_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket));
+ plug_xid = GDK_WINDOW_XID (icon_app_window);
+
+ display = gtk_widget_get_display (GTK_WIDGET (icon->priv->socket));
+ gdk_error_trap_push ();
+ _NET_WM_PID = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID");
+ result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), plug_xid,
+ _NET_WM_PID, 0, G_MAXLONG, False, XA_CARDINAL,
+ &type, &format, &nitems,
+ &bytes_after, (guchar **)&val);
+ if (!gdk_error_trap_pop () &&
+ result == Success &&
+ type == XA_CARDINAL &&
+ nitems == 1)
+ icon->priv->pid = *val;
+
+ if (val)
+ XFree (val);
+}
+
+static void
+shell_tray_icon_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
+
+ switch (prop_id)
+ {
+ case PROP_PID:
+ g_value_set_uint (value, icon->priv->pid);
+ break;
+
+ case PROP_TITLE:
+ g_value_set_string (value, icon->priv->title);
+ break;
+
+ case PROP_WM_CLASS:
+ g_value_set_string (value, icon->priv->wm_class);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+shell_tray_icon_class_init (ShellTrayIconClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (ShellTrayIconPrivate));
+
+ object_class->get_property = shell_tray_icon_get_property;
+ object_class->constructed = shell_tray_icon_constructed;
+ object_class->finalize = shell_tray_icon_finalize;
+
+ g_object_class_install_property (object_class,
+ PROP_PID,
+ g_param_spec_uint ("pid",
+ "PID",
+ "The PID of the icon's application",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_TITLE,
+ g_param_spec_string ("title",
+ "Title",
+ "The icon's window title",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_WM_CLASS,
+ g_param_spec_string ("wm-class",
+ "WM Class",
+ "The icon's window WM_CLASS",
+ NULL,
+ G_PARAM_READABLE));
+}
+
+static void
+shell_tray_icon_init (ShellTrayIcon *icon)
+{
+ icon->priv = G_TYPE_INSTANCE_GET_PRIVATE (icon, SHELL_TYPE_TRAY_ICON,
+ ShellTrayIconPrivate);
+}
+
+/*
+ * Public API
+ */
+ClutterActor *
+shell_tray_icon_new (ShellEmbeddedWindow *window)
+{
+ g_return_val_if_fail (SHELL_IS_EMBEDDED_WINDOW (window), NULL);
+
+ return g_object_new (SHELL_TYPE_TRAY_ICON,
+ "window", window,
+ NULL);
+}
--- /dev/null
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#ifndef __SHELL_TRAY_ICON_H__
+#define __SHELL_TRAY_ICON_H__
+
+#include "shell-gtk-embed.h"
+
+#define SHELL_TYPE_TRAY_ICON (shell_tray_icon_get_type ())
+#define SHELL_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_TRAY_ICON, ShellTrayIcon))
+#define SHELL_TRAY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_TRAY_ICON, ShellTrayIconClass))
+#define SHELL_IS_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_TRAY_ICON))
+#define SHELL_IS_TRAY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_TRAY_ICON))
+#define SHELL_TRAY_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_TRAY_ICON, ShellTrayIconClass))
+
+typedef struct _ShellTrayIcon ShellTrayIcon;
+typedef struct _ShellTrayIconClass ShellTrayIconClass;
+typedef struct _ShellTrayIconPrivate ShellTrayIconPrivate;
+
+struct _ShellTrayIcon
+{
+ ShellGtkEmbed parent;
+
+ ShellTrayIconPrivate *priv;
+};
+
+struct _ShellTrayIconClass
+{
+ ShellGtkEmbedClass parent_class;
+};
+
+
+GType shell_tray_icon_get_type (void) G_GNUC_CONST;
+ClutterActor *shell_tray_icon_new (ShellEmbeddedWindow *window);
+
+#endif /* __SHELL_TRAY_ICON_H__ */
#include "shell-tray-manager.h"
#include "na-tray-manager.h"
-#include "shell-gtk-embed.h"
+#include "shell-tray-icon.h"
#include "shell-embedded-window.h"
#include "shell-global.h"
GtkWidget *socket;
GtkWidget *window;
ClutterActor *actor;
- gboolean emitted_plugged;
} ShellTrayManagerChild;
enum {
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ShellTrayManagerClass, tray_icon_added),
NULL, NULL,
- gi_cclosure_marshal_generic,
- G_TYPE_NONE, 3,
- CLUTTER_TYPE_ACTOR,
- G_TYPE_STRING,
- G_TYPE_STRING);
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ CLUTTER_TYPE_ACTOR);
shell_tray_manager_signals[TRAY_ICON_REMOVED] =
g_signal_new ("tray-icon-removed",
G_TYPE_FROM_CLASS (klass),
ShellTrayManager *manager)
{
ShellTrayManagerChild *child;
- char *wm_class, *lower_wm_class;
- char *title;
- child = g_hash_table_lookup (manager->priv->icons, socket);
- /* Only emit this signal once; the point of waiting until we
- * get the first plugged notification is to be able to get the WM_CLASS
- * from the child window. But we don't want to emit this signal twice
- * if for some reason the socket gets replugged.
- */
- if (child->emitted_plugged)
- return;
- child->emitted_plugged = TRUE;
+ g_signal_handlers_disconnect_by_func (socket, on_plug_added, manager);
- na_tray_child_get_wm_class (NA_TRAY_CHILD (socket), NULL, &wm_class);
- if (!wm_class)
- return;
-
- title = na_tray_child_get_title (NA_TRAY_CHILD (socket));
+ child = g_hash_table_lookup (manager->priv->icons, socket);
- lower_wm_class = g_ascii_strdown (wm_class, -1);
+ child->actor = shell_tray_icon_new (SHELL_EMBEDDED_WINDOW (child->window));
g_signal_emit (manager, shell_tray_manager_signals[TRAY_ICON_ADDED], 0,
- child->actor, lower_wm_class, title);
- g_free (lower_wm_class);
- g_free (wm_class);
- g_free (title);
+ child->actor);
}
static void
{
ShellTrayManager *manager = user_data;
GtkWidget *win;
- ClutterActor *icon;
ShellTrayManagerChild *child;
/* We don't need the NaTrayIcon to be composited on the window we
*/
na_tray_child_set_composited (NA_TRAY_CHILD (socket), FALSE);
- win = shell_embedded_window_new ();
+ win = shell_embedded_window_new (manager->priv->stage);
gtk_container_add (GTK_CONTAINER (win), socket);
/* The colormap of the socket matches that of its contents; make
gtk_widget_show_all (win);
- icon = shell_gtk_embed_new (SHELL_EMBEDDED_WINDOW (win));
-
- child->actor = g_object_ref (icon);
g_hash_table_insert (manager->priv->icons, socket, child);
g_signal_connect (socket, "plug-added", G_CALLBACK (on_plug_added), manager);